package app.modules.security.business.service.permission;

import app.modules.common.constant.CommonLockConstants;
import app.modules.security.business.service.resourcee.ResourceService;
import app.modules.security.business.service.SyncRbacCacheService;
import app.modules.security.constant.SecurityLockConstants;
import app.modules.security.dto.web.resource.WebResourceDTO;
import app.modules.security.persistence.dao.PermissionResourceRelationDAO;
import app.modules.security.persistence.dao.ResourceDAO;
import jasmine.framework.common.util.CheckUtil;
import jasmine.framework.common.util.CollectionUtil;
import jasmine.framework.lock.annotation.DistributedLock;
import jasmine.security.rbac.model.SecPermission;
import jasmine.security.rbac.model.SecPermissionResourceRelation;
import jasmine.security.rbac.model.SecResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author mh.z
 */
@Service
public class PermissionResourceRelationService {
    private PermissionResourceRelationDAO permissionResourceRelationDAO;
    private ResourceDAO resourceDAO;
    private ResourceService resourceService;
    private SyncRbacCacheService syncRbacCacheService;

    public PermissionResourceRelationService(PermissionResourceRelationDAO permissionResourceRelationDAO,
                                             ResourceDAO resourceDAO,
                                             ResourceService resourceService,
                                             SyncRbacCacheService syncRbacCacheService) {
        this.permissionResourceRelationDAO = permissionResourceRelationDAO;
        this.resourceDAO = resourceDAO;
        this.resourceService = resourceService;
        this.syncRbacCacheService = syncRbacCacheService;
    }

    /**
     * 查询指定权限的所有已分配资源
     *
     * @param permissionId
     * @return
     */
    public List<WebResourceDTO> listAssignedResources(Long permissionId) {
        List<WebResourceDTO> recordList = permissionResourceRelationDAO.listAssignedResources(permissionId);
        resourceService.populateWebResourceDTOs(recordList);

        return recordList;
    }

    /**
     * 分配资源
     *
     * @param permissionId
     * @param resourceIds
     */
    @DistributedLock(category = SecurityLockConstants.LOCK_CATEGORY_PERMISSION_ASSIGN_RESOURCES, key = CommonLockConstants.LOCK_KEY_ALL)
    @Transactional(rollbackFor = Exception.class)
    public void assignResource(Long permissionId, List<Long> resourceIds) {
        CheckUtil.notNull(permissionId, "permissionId null");
        CheckUtil.notNull(resourceIds, "resourceIds null");

        // 删除指定权限的所有资源分配关系
        permissionResourceRelationDAO.deleteByPermissionId(permissionId);

        if (CollectionUtil.isNotEmpty(resourceIds)) {
            List<SecResource> resourceList = resourceDAO.listByIds(resourceIds);
            resourceIds = CollectionUtil.mapToList(resourceList, SecResource::getId);

            List<SecPermissionResourceRelation> newRecordList = CollectionUtil.mapToList(resourceIds, (resourceId) -> {
                SecPermissionResourceRelation newRecord = new SecPermissionResourceRelation();
                newRecord.setPermissionId(permissionId);
                newRecord.setResourceId(resourceId);

                return newRecord;
            });

            if (CollectionUtil.isNotEmpty(newRecordList)) {
                // 保存权限和资源的分配关系
                permissionResourceRelationDAO.saveBatch(newRecordList);
            }
        }

        // 同步缓存
        syncRbacCacheService.syncFunctionsWithResourceIdCache(SecPermission.class, permissionId);
    }

}
